#include "qusermesh.h"
#include <QVector>
#include <QMap>
#include <QMatrix4x4>
#include <math.h>
#define PI 3.14159265358979

QUserMesh::QUserMesh()
{
    qDebug("QUserMesh::QUserMesh(...)");
}

void QUserMesh::Init()
{
}

void QUserMesh::SetSize(int ssize, int voff, int noff, int coff, int uvoff)
{
    m_structsize = ssize;
    m_vertexoff = voff;
    m_normaloff = noff;
    m_coloroff = coff;
    m_uvoff = uvoff;
}

const int QUserMesh::size() const
{
    return this->m_vertices.count();
}

float *QUserMesh::GetVertexInfo(int index, int offset)
{
    return &this->m_vertices[index*m_structsize+offset];
}

const QVector<uint> QUserMesh::SubIndice(int key) const
{
    if(m_subindices.contains(key))
        return m_subindices[key];
    else
        return QVector<uint>();
}

void QUserMesh::SubIBOIDs(uint *subiboids, int size)
{
    subiboIDs.clear();
    for (int i=0;i<size;i++)
        subiboIDs.append(subiboids[i]);
}

void QUserMesh::GeneratePlane(float x, float y, QVector3D normal, float z, int a, int b)
{
    SetSize(6,0,3,0,0);
    float px,py;
    px = x/2;
    py = y/2;
    float rrow = 0;
    float rcol = 0;
    QVector3D point[4];
    if(normal.x()>0)
    {
        point[0]=QVector3D(z,py,px);
        point[1]=QVector3D(z,py,-px);
        point[2]=QVector3D(z,-py,px);
        point[3]=QVector3D(z,-py,-px);
    }else if(normal.x()<0)
    {
        point[0]=QVector3D(z,py,-px);
        point[1]=QVector3D(z,py,px);
        point[2]=QVector3D(z,-py,-px);
        point[3]=QVector3D(z,-py,px);
    }else if(normal.y()>0)
    {
        point[0]=QVector3D(-px,z,-py);
        point[1]=QVector3D(px,z,-py);
        point[2]=QVector3D(-px,z,py);
        point[3]=QVector3D(px,z,py);
    }else if(normal.y()<0)
    {
        point[0]=QVector3D(-px,z,py);
        point[1]=QVector3D(px,z,py);
        point[2]=QVector3D(-px,z,-py);
        point[3]=QVector3D(px,z,-py);
    }else if(normal.z()>0)
    {
        point[0]=QVector3D(-px,py,z);
        point[1]=QVector3D(px,py,z);
        point[2]=QVector3D(-px,-py,z);
        point[3]=QVector3D(px,-py,z);
    }else if(normal.z()<0)
    {
        point[0]=QVector3D(px,py,z);
        point[1]=QVector3D(-px,py,z);
        point[2]=QVector3D(px,-py,z);
        point[3]=QVector3D(-px,-py,z);
    }

    for (int i=0;i<b+1;i++)
    {
        rcol = i*1/b;
        QVector3D tempr0 = point[0] + rcol * (point[2]-point[0]);
        QVector3D tempr1 = point[1] + rcol * (point[3]-point[1]);
        for (int j=0;j<a+1;j++)
        {
            rrow = j*1/a;
            QVector3D final = tempr0 + rrow * (tempr1-tempr0);
            m_vertices.append(final.x());
            m_vertices.append(final.y());
            m_vertices.append(final.z());
            m_vertices.append(normal.x());
            m_vertices.append(normal.y());
            m_vertices.append(normal.z());
            if (i<b&&j<a)
            {
                m_indices<<i*(b+1)+j<<i*(b+1)+j+1<<(i+1)*(b+1)+j;
                m_indices<<(i+1)*(b+1)+j<<i*(b+1)+j+1<<(i+1)*(b+1)+j+1;
            }
        }
    }
}

void QUserMesh::GenerateSphere(float r, int a, int b)
{
    if (a<2)a=8;
    if (b<3)b=24;

    m_vertices<<0<<r<<0;
    m_vertices<<0<<r<<0;

    float phi = PI/a;
    float theta = 2*PI/b;
    for (int i=1;i<a;i++)
    {
        float angle = PI/2-phi*i;
        float y = r*sinf(angle);
        float rp = r*cosf(angle);
        int last = (i-2)*b+1;
        int current = (i-1)*b+1;
        for (int j=0;j<b;j++)
        {
            m_vertices<<cosf(theta*j)*rp<<y<<sinf(theta*j)*rp;
            m_vertices<<cosf(theta*j)*rp<<y<<sinf(theta*j)*rp;
            if(i==1)
            {
                if(j>0)
                    m_indices<<j+1<<0<<j;
                if(j==b-1)
                    m_indices<<1<<0<<b;
            }else{
                if(j>0)
                {
                    int llli = last+j-1;
                    int llci = last+j;
                    int clli = current+j-1;
                    int clci = current+j;
                    m_indices<<llci<<llli<<clli;
                    m_indices<<llci<<clli<<clci;
                }
                if(j==b-1)
                {
                    int llci = last+j;
                    int clci = current+j;
                    m_indices<<last<<llci<<clci;
                    m_indices<<last<<clci<<current;
                }
            }
            if(i==a-1)
            {
                if(j>0)
                    m_indices<<current+j<<current+j-1<<current+b;
                if(j==b-1)
                    m_indices<<current<<current+j<<current+b;
            }
        }
    }
    m_vertices<<0<<-r<<0;
    m_vertices<<0<<-r<<0;
    SetSize(6,0,3,0,0);
}

void QUserMesh::Translate(QVector3D vec3d)
{
    int ss = m_structsize;
    int vo = m_vertexoff;
    float* data = m_vertices.data();
    for (int i=0;i<m_vertices.size()/ss;i++)
    {
        float* cdata = &data[i*ss];
        cdata[vo]+=vec3d.x();
        cdata[vo+1]+=vec3d.y();
        cdata[vo+2]+=vec3d.z();
    }
}

void QUserMesh::Rotate(QMatrix4x4 mat4x4)
{
    int ss = m_structsize;
    int vo = m_vertexoff;
    int no = m_normaloff;
    float* data = m_vertices.data();
    for (int i=0;i<m_vertices.size()/ss;i++)
    {
        float* cdata = &data[i*ss];
        QVector3D v3ddata(cdata[vo+0],cdata[vo+1],cdata[vo+2]);
        v3ddata = mat4x4*v3ddata;
        cdata[vo+0]=v3ddata.x();
        cdata[vo+1]=v3ddata.y();
        cdata[vo+2]=v3ddata.z();
        QVector3D v3dnormal(cdata[no+0],cdata[no+1],cdata[no+2]);
        cdata[no+0]=v3dnormal.x();
        cdata[no+1]=v3dnormal.y();
        cdata[no+2]=v3dnormal.z();
    }
}

void QUserMesh::GaussianNoise(float mean, float std)
{
    int ss = m_structsize;
    int vo = m_vertexoff;
    int no = m_normaloff;
    float* data = m_vertices.data();
    for (int i=0;i<m_vertices.size()/ss;i++)
    {
        float* cdata = &data[i*ss];
        QVector3D v3dnormal(cdata[no+0],cdata[no+1],cdata[no+2]);
        v3dnormal.normalize();
        v3dnormal*=normrnd(mean,std);
        cdata[vo]+=v3dnormal.x();
        cdata[vo+1]+=v3dnormal.y();
        cdata[vo+2]+=v3dnormal.z();
    }
}

